import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import linear_kernel
from collections import Counter
from spellchecker import SpellChecker
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
import ast
import re
import argparse
import sys

merged_data = pd.read_csv("updata/merge_data.csv", na_filter=False)

def al3(search,merged_data):
    # 输入新的电影名称
    movie_title = search
    # 使用正则表达式去除非字母字符
    new_movie_title = re.sub(r'[^a-zA-Z0-9\s]', '', movie_title)

    # 定义一个移除所有english stop words如'the', 'a'的转换器
    tfidf = TfidfVectorizer(stop_words='english')

    # 将标题和概述用空格隔开并存储到一个数组（列表）中
    title_list = ((merged_data['title']+' ')*5+ ' '+ (merged_data['comb'])+' '+(merged_data['overview']+' ')).tolist()
    #title_list = ((merged_data['title']+' ')*2+ ' '+ (merged_data['comb'])).tolist()

    title_list.append(new_movie_title)

    # 构建 TF-IDF 矩阵
    tfidf = TfidfVectorizer(stop_words='english')
    tfidf_matrix = tfidf.fit_transform(title_list)

    # 输出矩阵形状
    tfidf_matrix.shape

        # 获取词汇表
    feature_names = tfidf.get_feature_names_out()

    # 获取新电影的TF-IDF向量
    new_movie_vector = tfidf_matrix[-1]

    # 将TF-IDF向量转换为词素集合
    new_movie_tokens = set(feature_names[i] for i in new_movie_vector.indices)

    # 获取所有其他电影的词素集合
    other_movie_tokens = set()
    for doc in tfidf_matrix[:-1]:
        other_movie_tokens.update(feature_names[i] for i in doc.indices)

    # 计算新电影词素集合中在其他电影词素集合中出现的词素集合
    common_tokens = new_movie_tokens.intersection(other_movie_tokens)

    # 计算余弦相似度，仅计算新电影与其他电影的相似度
    cosine_sim_1 = linear_kernel(tfidf_matrix[-1:], tfidf_matrix[:-1])

    # 获取与新电影最相似的前20个电影
    sim_scores_1 = list(enumerate(cosine_sim_1[0]))

    # 定义一个移除所有english stop words如'the', 'a'的转换器
    tfidf = TfidfVectorizer(stop_words='english')
    # 清理 NaN 值，将其替换为空字符串
    keywords_list = (merged_data['keywords']).tolist()
    keywords_list.append(new_movie_title)
    # # 打印前5个组合后的结果以进行验证
    # print("前5个组合后的结果:", keywords_list[:5])

    # 构建 TF-IDF 矩阵
    tfidf = TfidfVectorizer(stop_words='english')
    tfidf_matrix_2 = tfidf.fit_transform(keywords_list)

    # 输出矩阵形状
    tfidf_matrix_2.shape

        # 获取词汇表
    feature_names = tfidf.get_feature_names_out()

    # 获取新keywords的TF-IDF向量
    new_keywords_vector = tfidf_matrix_2[-1]

    # 将TF-IDF向量转换为词素集合
    new_keywords_tokens = set(feature_names[i] for i in new_keywords_vector.indices)

    # 获取所有其他电影的词素集合
    other_keywords_tokens = set()
    for doc in tfidf_matrix_2[:-1]:
        other_keywords_tokens.update(feature_names[i] for i in doc.indices)

    # 计算新电影词素集合中在其他电影词素集合中出现的词素集合
    common_tokens_2 = new_keywords_tokens.intersection(other_keywords_tokens)

    # 输出新电影词素集合中在其他电影词素集合中出现的词素集合

    # 计算余弦相似度，仅计算新电影与其他关键词的相似度
    cosine_sim_2 = linear_kernel(tfidf_matrix_2[-1:], tfidf_matrix_2[:-1])

    # 计算两个集合的交集
    intersection_tokens = common_tokens.intersection(common_tokens_2)

    ##计算集合的并集
    # 使用 union() 方法
    union_set = common_tokens.union(common_tokens_2)
    union_set = union_set.union(intersection_tokens)
    
    ##计算参数的方法
    if(len(common_tokens_2)==len(intersection_tokens)==len(union_set)):
        C2 = 0.5
    elif(len(common_tokens_2)==len(intersection_tokens)==0):
        C2 = 0
    elif(len(common_tokens)==len(intersection_tokens)==0):
        C2 = 1
    else:
        C2 = (len(common_tokens_2)+len(intersection_tokens)/2)/(len(common_tokens)+len(common_tokens_2))

    # 余弦结果获取与输入最相似的电影
    sim_scores_1 = list(enumerate(cosine_sim_1[0]))
    # 获余弦结果取与输入最相似的关键词
    sim_scores_2 = list(enumerate(cosine_sim_2[0]))

    # 计算加权平均相似度分数
    combined_sim_scores = [(idx, (1-C2)* score1 + C2 * score2) for (idx, score1), (_, score2) in zip(sim_scores_1, sim_scores_2)]

    # 对合并后的相似度分数进行排序，取得最相似的条目
    combined_sim_scores = sorted(combined_sim_scores, key=lambda x: x[1], reverse=True)

    # 筛选出分数大于0的条目
    non_zero_scores = [item for item in combined_sim_scores if item[1] > 0]

    # 对这些条目按分数进行降序排序
    non_zero_scores.sort(key=lambda x: x[1], reverse=True)

    top_n_indexes = [item[0] for item in non_zero_scores]

    scores = [score[1] for score in non_zero_scores]

    # 从merged_data中获取相应的id和title
    top_n_data = merged_data.loc[top_n_indexes, ['id', 'title','popularity','vote_average','vote_count','ad']]

    # 添加分数列
    top_n_data['score'] = scores  # 直接添加列
    top_n_data = top_n_data[:10]

    # 第一步：将top_n_data的ID列转换为浮点数类型（处理小数形式）
    top_n_data['id'] = pd.to_numeric(top_n_data['id'], errors='coerce')

    # 第二步：删除无法转换为数值的ID（NaN）
    top_n_data = top_n_data.dropna(subset=['id'])

    # 第三步：将浮点数转换为整数类型（取整去掉小数部分）
    top_n_data['id'] = top_n_data['id'].astype(int)

    # 确保需要计算的列都是数值类型
    columns_to_convert = ['popularity', 'vote_average', 'vote_count', 'score','ad']
    for column in columns_to_convert:
        top_n_data[column] = pd.to_numeric(top_n_data[column], errors='coerce')

    # 删除转换过程中出现的NaN值
    top_n_data = top_n_data.dropna(subset=columns_to_convert)
    # 定义映射范围和权重参数
    mapping = {
        'popularity': {'range': (0, 10), 'weight': 0.5},
        'ad': {'range': (1, 1), 'weight': 0.1},
        'vote_average': {'range': (0, 10), 'weight': 2},
        'vote_count': {'range': (0, 10000), 'weight': 0.0008},
        'score': {'range': (0, 1), 'weight': 10}
    }

    def map_to_range(value, original_min, original_max, target_min, target_max):
        """ 将值从原始范围映射到目标范围 """
        original_range = original_max - original_min
        target_range = target_max - target_min
        if original_range == 0:
            original_range = target_min
        normalized_value = (value - original_min) / original_range  # 归一化到 [0, 1]
        mapped_value = target_min + (normalized_value * target_range)  # 映射到目标范围
        return mapped_value
    # 初始化加权和列
    top_n_data['weighted_sum'] = 0

    # 原始范围可以从数据的实际最小值和最大值中计算
    for column, params in mapping.items():
        target_min, target_max = params['range']
        weight = params['weight']
        original_min = top_n_data[column].min()
        original_max = top_n_data[column].max()
        
        # 映射值并计算加权和
        top_n_data['weighted_sum'] += map_to_range(top_n_data[column], original_min, original_max, target_min, target_max) * weight
        #print( map_to_range(top_n_data[column], original_min, original_max, target_min, target_max))

    # 根据加权和排序
    data_sorted = top_n_data.sort_values(by='weighted_sum', ascending=False)

    # 提取 id 列
    id_list = data_sorted['id'].tolist()

    # 输出 id 列表
    print(id_list)

if len(sys.argv) < 1:
   sys.exit(-1)

search = sys.argv[1]

al3(search,merged_data)
